package com.yuandian.management.service.impl;


import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.alibaba.cloud.nacos.NacosConfigManager;
import com.alibaba.nacos.api.exception.NacosException;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yuandian.api.management.entity.*;
import com.yuandian.bpm.common.core.util.R;
import com.yuandian.bpm.common.security.util.SecurityUtils;
import com.yuandian.management.enums.*;
import com.yuandian.management.mapper.ConfProbeManageMapper;
import com.yuandian.management.service.*;
import com.yuandian.management.socket.ProbeSocketRequest;
import com.yuandian.management.socket.ProbeSocketResponse;
import com.yuandian.management.socket.client.DefaultSocketClient;
import com.yuandian.management.socket.client.SocketClient;
import com.yuandian.management.utils.DateTool;
import com.yuandian.management.utils.JacksonUtil;
import com.yuandian.management.utils.XmlUtils;
import com.yuandian.management.vo.ProbeRunStatusKvsEo;
import com.yuandian.management.vo.SyncBusinessRespDto;
import com.yuandian.utils.StringUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.dom4j.io.OutputFormat;
import org.dom4j.io.XMLWriter;
import org.ini4j.Ini;
import org.ini4j.Wini;
import org.springframework.beans.BeanUtils;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.io.*;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 探针采集配置表-Service实现
 * @author zfsn
 * @date 2023-4-17
 */
@Slf4j
@Service
public class ConfProbeManageServiceImpl extends ServiceImpl<ConfProbeManageMapper, ConfProbeManage>
		implements ConfProbeManageService {
	private static final String lock = "insert_lock";

	// key为设备id，值为 同步中，同步成功，同步失败
	public static HashMap<String,String> probeMaps=new HashMap<>();


	@Resource
	private ConfProbeInterfaceService probeInterfaceService;


	@Resource
	private ConfProtocolService confProtocolService;

	@Resource
	private ConfResourceService confResourceService;

	@Resource
	private ConfProbeManageMapper probeManageMapper;

	@Resource
	private ConfKeywordService confKeywordService;

	@Resource
	private ConfExclusiveIndicatorService confExclusiveIndicatorService;

	@Resource
	private ConfDecryptService confDecryptService;

	@Resource
	private ConfComponentIpService confComponentIpService;

	@Resource
	private NacosConfigManager nacosConfigManager;


//	public static void main(String[] args) {
//		String s = "[business_common]\n" +
//				"device_is_active=true\n" +
//				"device_name=eth0\n" +
//				"device_type=ethternet\n" +
//				"device_id=1\n" +
//				"device_alias=if1";
//		Props props = new Props();
//		props.load(new InputStreamReader().read(s, 0, s.length()));
//
//	}


	/**
	 * 分页查询探针配置管理页面
	 *
	 * @param reqDto
	 * @return
	 */
	@Override
	public Page<ConfProbeManage> queryPageInfo(ConfProbeManage reqDto) {
		//同步过程中，不能去请求探针是否存活，否则会异常，60秒后，可以去请求探针是否存活
//		if (!ConfProbeManageController.isWork&&ConfProbeManageController.finishWorkDate!=null&&(new Date()).getTime()-ConfProbeManageController.finishWorkDate.getTime()>60*1000){
//			ipMap.clear();
//		}
//		if (!ConfProbeManageController.isWork&&ConfProbeManageController.finishWorkDate==null){
//			ipMap.clear();
//		}
		Page<ConfProbeManage> confProbeManagePage = probeManageMapper.selectByCondition(new Page<>(reqDto.getPageNum(), reqDto.getPageSize()), reqDto);
		List<ConfProbeManage> resultEos = confProbeManagePage.getRecords();
		if (CollectionUtils.isNotEmpty(resultEos)) {
			List<ConfProbeManage> respDtos = new ArrayList<>();
			for (ConfProbeManage resultEo : resultEos) {
				ConfProbeManage respDto = new ConfProbeManage();
				Map<String, Integer> ipAndStatusMap = new HashMap<>();
				if (ipAndStatusMap.get(resultEo.getIp()) == null) {
					respDto.setId(resultEo.getId());
					//设置超时时间( 以下代码迁移 from 2.5且做适当改造)
					try {
						String propertySource = nacosConfigManager.getConfigService().getConfig(resultEo.getIp() + "_common_config.ini", "UDPROBE_CONF", 1000);
						if(propertySource == null){
							log.info("探针ip:{} --获取探针状态失败!", resultEo.getIp());
							respDto.setProbeStatus(ProbeStatusEnum.DEATH.getStatus());
						}else {
								ByteArrayInputStream inputStream = new ByteArrayInputStream(propertySource.getBytes());
								Ini wini = new Wini(inputStream);
								if (wini.containsKey("business_common")) {
									Ini.Section businessCommon = wini.get("business_common");
									if (Objects.equals(businessCommon.get("device_is_active"), "true")) {
										log.info("探针ip:" + resultEo.getIp() + "--获取探针状态--" + "激活");
										respDto.setProbeStatus(ProbeStatusEnum.ACTIVE.getStatus());
									}else {
										log.info("探针ip:" + resultEo.getIp() + "--获取探针状态--返回码:" + "停止");
										respDto.setProbeStatus(ProbeStatusEnum.DEATH.getStatus());
									}
								}
							}
						ipAndStatusMap.put(resultEo.getIp(), respDto.getProbeStatus()); // 更新该IP对应的探针值
						respDtos.add(respDto);
					} catch (Exception e) {
						e.printStackTrace();
						// 探针不存在，修改为失活状态
						respDto.setId(resultEo.getId());
						respDto.setProbeStatus(ProbeStatusEnum.DEATH.getStatus());
						ipAndStatusMap.put(resultEo.getIp(), respDto.getProbeStatus());
						respDtos.add(respDto);
					}
				} else {
					respDto.setId(resultEo.getId());
					respDto.setProbeStatus(ipAndStatusMap.get(resultEo.getIp()));
					respDtos.add(respDto);
				}
			}
			List<Integer> activeIds = new ArrayList<>();
			List<Integer> deathIds = new ArrayList<>();
			// 更新mysql表
			for (ConfProbeManage respDto : respDtos) {

				if (Objects.equals(respDto.getProbeStatus(), ProbeStatusEnum.ACTIVE.getStatus())) {
					activeIds.add(respDto.getId());
				} else {
					deathIds.add(respDto.getId());
				}
			}
//            List<Integer> activeIds = reqDtos.stream().filter(eo -> ProbeStatusEnum.ACTIVE.getStatus().equals(eo.getIsStatus())).map(ProbeManageEo::getId).collect(Collectors.toList());
//            List<Integer> deathIds = reqDtos.stream().filter(eo -> ProbeStatusEnum.DEATH.getStatus().equals(eo.getIsStatus())).map(ConfProbeManage::getId).collect(Collectors.toList());
			if (CollectionUtils.isNotEmpty(activeIds)) {
				probeManageMapper.batchUpdateStatus(activeIds, ProbeStatusEnum.ACTIVE.getStatus());
			}
			if (CollectionUtils.isNotEmpty(deathIds)) {
				probeManageMapper.batchUpdateStatus(deathIds, ProbeStatusEnum.DEATH.getStatus());
			}
			// 更新数据库探针状态后重新获取探针列表数据
			confProbeManagePage = probeManageMapper.selectByCondition(new Page<>(reqDto.getPageNum(), reqDto.getPageSize()), reqDto);
			resultEos = confProbeManagePage.getRecords();
			if (CollectionUtils.isNotEmpty(resultEos)) {
				respDtos = new ArrayList<>();
				for (ConfProbeManage resultEo : resultEos) {
					ConfProbeManage respDto = new ConfProbeManage();
					BeanUtils.copyProperties(resultEo, respDto);
					//加入探针同步业务配置状态
					respDto.setProbeSyncBusiStatus(probeMaps.get(respDto.getIp()));
					respDtos.add(respDto);
				}
				confProbeManagePage.setRecords(respDtos);
				return confProbeManagePage;
			}
		}
		return confProbeManagePage;
	}

	/**
	 * 批量查询探针状态
	 *
	 * @param idList
	 * @return
	 */
	@Override
	public List<ConfProbeManage> queryStatusForList(List<Integer> idList) {
		List<ConfProbeManage> respDtos = new ArrayList<>();
		List<ConfProbeManage> resultEos = probeManageMapper.selectByIds(idList);
		for (ConfProbeManage resultEo : resultEos) {
			ConfProbeManage respDto = new ConfProbeManage();
			respDto.setId(resultEo.getId());

			try {

				String propertySource = nacosConfigManager.getConfigService().getConfig(resultEo.getIp() + "_common_config.ini", "UDPROBE_CONF", 1000);
				if(propertySource == null){
					log.info("探针ip:{} --获取探针状态失败!", resultEo.getIp());
					respDto.setProbeStatus(ProbeStatusEnum.DEATH.getStatus());
				}else {
					ByteArrayInputStream inputStream = new ByteArrayInputStream(propertySource.getBytes());
					Ini wini = new Wini(inputStream);
					if (wini.containsKey("business_common")) {
						Ini.Section businessCommon = wini.get("business_common");
						if (Objects.equals(businessCommon.get("device_is_active"), "true")) {
							log.info("探针ip:" + resultEo.getIp() + "--获取探针状态--" + "激活");
							respDto.setProbeStatus(ProbeStatusEnum.ACTIVE.getStatus());
						}else {
							log.info("探针ip:" + resultEo.getIp() + "--获取探针状态--返回码:" + "停止");
							respDto.setProbeStatus(ProbeStatusEnum.DEATH.getStatus());
						}
					}
				}
				respDtos.add(respDto);
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		// 更新mysql表
		List<ConfProbeManage> reqDtos = new ArrayList<>();
		for (ConfProbeManage respDto : respDtos) {
			ConfProbeManage eo = new ConfProbeManage();
			eo.setId(respDto.getId());
			eo.setProbeStatus(respDto.getProbeStatus());
			reqDtos.add(eo);
		}
		List<Integer> activeIds = reqDtos.stream().filter(eo -> ProbeStatusEnum.ACTIVE.getStatus().equals(eo.getIsStatus())).map(ConfProbeManage::getId).collect(Collectors.toList());
		List<Integer> deathIds = reqDtos.stream().filter(eo -> ProbeStatusEnum.DEATH.getStatus().equals(eo.getIsStatus())).map(ConfProbeManage::getId).collect(Collectors.toList());
		if (CollectionUtils.isNotEmpty(activeIds)) {
			probeManageMapper.batchUpdateStatus(activeIds, ProbeStatusEnum.ACTIVE.getStatus());
		}
		if (CollectionUtils.isNotEmpty(deathIds)) {
			probeManageMapper.batchUpdateStatus(deathIds, ProbeStatusEnum.DEATH.getStatus());
		}
		return respDtos;
	}

	/**
	 * 详情
	 *
	 * @param id
	 * @return
	 */
	@Override
	public ConfProbeManage probeDetail(Integer id) {
		ConfProbeManage eo = probeManageMapper.queryById(id);
		if (null != eo) {
			ConfProbeManage respDto = new ConfProbeManage();
			BeanUtils.copyProperties(eo, respDto);
			return respDto;
		}
		return null;
	}

	/**
	 * 查询探针运行信息且更新运行信息
	 *
	 * @param id
	 * @return
	 */
	@Override
	public ConfProbeManage queryProbeRunning(Integer id) {
		ConfProbeManage probeManageEo = probeManageMapper.queryById(id);
		if (null != probeManageEo) {
			// 查询探针状态,如果有新数据则会更新到数据库中
			ConfProbeManage respDto = queryProbeStatusBeforeUpdate(probeManageEo);
			return respDto;
		}
		return null;
	}

	/**
	 * 查询探针状态,且更新记录
	 *
	 * @param probe
	 * @return
	 */
	private ConfProbeManage queryProbeStatusBeforeUpdate(ConfProbeManage probe) {
		DefaultSocketClient.proTimeOut = 60;//设置超时时间
		SocketClient socketClient = new DefaultSocketClient(AppIdEnum.getAppIdEnumValue("0"), ModuleEnum.getModuleIdEnumValue("2"), Integer.parseInt(OperTypeEnum.getOperTypeEnumValue("1")));
		ConfProbeManage respDto = new ConfProbeManage();
		try {
			ProbeSocketResponse<ProbeRunStatusKvsEo> psr = socketClient.execute(new ProbeSocketRequest(1, "", new ArrayList<>()), probe.getIp());
			if (null != psr) {
				Map<String, Integer> kvsMap = (Map<String, Integer>) psr.getKvs();
				log.info("接收到的探针运行状况的数据：" + JacksonUtil.objectToString(kvsMap));
				if (null != kvsMap && kvsMap.size() > 0) {
					probe.setProbeStatus(1);       //探针运行状态
					probe.setCpuUtilization(Double.parseDouble(kvsMap.get("cpu_rate") + "") / 100 + "%");   //cpu使用率
					probe.setDiskSize(kvsMap.get("disk_size") + "MB");         //硬盘大小
					probe.setDiskUtilization(Double.parseDouble(kvsMap.get("cpu_rate") + "") / 100 + "%");  //硬盘利用率
					probe.setMemorySize(kvsMap.get("mem_size") + "MB");       //内存大小
					probe.setMemoryUtilization(Double.parseDouble(kvsMap.get("mem_rate") + "") / 100 + "%");//内存使用率
					probeManageMapper.updateProbeRunInfo(probe);
					BeanUtils.copyProperties(probe, respDto);
					return respDto;
				} else {
					probeManageMapper.batchUpdateStatus(Arrays.asList(probe.getId()), ProbeStatusEnum.DEATH.getStatus());
				}
			}
		} catch (Exception e) {
			log.error("[探针采集配置管理][查询探针运行详情]出现异常", e);
		}
		BeanUtils.copyProperties(probe, respDto);
		respDto.setProbeStatus(ProbeStatusEnum.DEATH.getStatus());
		return respDto;
	}

	/**
	 * 新增探针采集配置
	 *
	 * @param reqDto
	 * @return
	 */
	@Override
	public R saveProbe(ConfProbeManage reqDto) {
		ConfProbeManage eo = new ConfProbeManage();
		BeanUtils.copyProperties(reqDto, eo);
		// 查询探针状态
		try {

			//处理探针同步的返回结果
			String propertySource = nacosConfigManager.getConfigService().getConfig(eo.getIp() + "_common_config.ini", "UDPROBE_CONF", 1000);


			//如果获取不到相关配置文件, 也默认 获取探针失败
			if(propertySource == null){
				log.info("探针ip:{} --获取探针状态失败!", eo.getIp());
				eo.setIsStatus(ProbeStatusEnum.DEATH.getStatus());
			}else {
				ByteArrayInputStream inputStream = new ByteArrayInputStream(propertySource.getBytes());
				Ini wini = new Wini(inputStream);
				if (wini.containsKey("business_common")) {
					Ini.Section businessCommon = wini.get("business_common");
					if (Objects.equals(businessCommon.get("device_is_active"), "true")) {
						log.info("探针ip:" + eo.getIp() + "--获取探针状态--" + "激活");
						eo.setIsStatus(ProbeStatusEnum.ACTIVE.getStatus());
					}else {
						log.info("探针ip:" + eo.getIp() + "--获取探针状态--返回码:" + "停止");
						eo.setIsStatus(ProbeStatusEnum.DEATH.getStatus());
					}
				}
			}
		} catch (Exception e) {
			log.info("探针ip" + eo.getIp() + "..连接服务器失败！", e);
			// Ip对应的探针不存在设置状态为失活
			eo.setIsStatus(ProbeStatusEnum.DEATH.getStatus());
		}
		eo.setCreateBy(getUserName());
		// ,通过 ip+name 校验唯一
		try {
			probeManageMapper.save(eo);
			// 保存接口信息
//			ConfProbeManage newEo = probeManageMapper.selectByUniqueKey(eo.getIp(), eo.getProbeName());
			probeInterfaceService.checkInterfaceInfo(eo.getId(), eo);
			return R.ok("新增探针信息成功");
		} catch (Exception e) {
			log.error("[探针采集配置管理][新增探针采集配置]出现异常", e);
			if (e instanceof DuplicateKeyException) {
				return R.failed("相同IP下设备名称不能重复或者为空");
			} else {
				return R.failed(e.getMessage());
			}
		}
	}

	/**
	 * 编辑探针采集配置
	 *
	 * @param reqDto
	 * @return
	 */
	@Override
	public R updateProbeDetail(ConfProbeManage reqDto) {
		// 查询
		Integer probeId = reqDto.getId();
		ConfProbeManage eo = probeManageMapper.queryById(probeId);
		BeanUtils.copyProperties(reqDto, eo);
		try {
			String propertySource = nacosConfigManager.getConfigService().getConfig(eo.getIp() + "_common_config.ini", "UDPROBE_CONF", 1000);
			//如果获取不到相关配置文件, 也默认 获取探针失败
			if(propertySource == null){
				log.info("探针ip:{} --获取探针状态失败!", eo.getIp());
				eo.setProbeStatus(ProbeStatusEnum.DEATH.getStatus());
			}else {
				ByteArrayInputStream inputStream = new ByteArrayInputStream(propertySource.getBytes());
				Ini wini = new Wini(inputStream);
				if (wini.containsKey("business_common")) {
					Ini.Section businessCommon = wini.get("business_common");
					if (Objects.equals(businessCommon.get("device_is_active"), "true")) {
						log.info("探针ip:" + eo.getIp() + "--获取探针状态--" + "激活");
						eo.setProbeStatus(ProbeStatusEnum.ACTIVE.getStatus());
					}else {
						log.info("探针ip:" + eo.getIp() + "--获取探针状态--返回码:" + "停止");
						eo.setProbeStatus(ProbeStatusEnum.DEATH.getStatus());
					}
				}
			}
		} catch (Exception e) {
			log.info("探针ip" + eo.getIp() + "..连接服务器失败！", e);
		}
		// 更新
		try {
			probeManageMapper.updateInfo(eo);
			probeInterfaceService.checkInterfaceInfo(probeId, eo);
			return R.ok(null);
		} catch (Exception e) {
			log.error("[探针采集配置管理][编辑探针采集配置]出现异常", e);
			if (e instanceof DuplicateKeyException) {
				return R.failed("相同IP下设备名称不能重复或者为空");
			} else {
				return R.failed(e.getMessage());
			}
		}
	}



	/**
	 * 查询探针协议配置列表
	 *
	 * @param reqDto
	 * @return
	 */
	@Override
	public Page<ConfProtocol> queryProbeProtocol(ConfProbeManage reqDto) {
		Page<ConfProtocol> page = new Page<>(reqDto.getPageNum(), reqDto.getPageSize());
		if (StringUtils.isNotBlank(reqDto.getProtocolName())) {
			ConfProtocol reqEo = new ConfProtocol();
			reqEo.setName(reqDto.getProtocolName());
			QueryWrapper<ConfProtocol> queryWrapper = new QueryWrapper<>();
			queryWrapper.like("name", reqEo.getName());
			return confProtocolService.page(page, queryWrapper);
		} else {
			return confProtocolService.page(page);
		}
	}

	/**
	 * 批量删除配置
	 *
	 * @param ids
	 * @return
	 */
	@Override
	public R delProbe(List<Integer> ids) {
		if (CollectionUtils.isNotEmpty(ids)) {
			probeManageMapper.deleteProbeByIds(ids);
			probeInterfaceService.deleteInterfaceByIds(ids);
			return R.ok("删除成功");
		}
		return R.ok(null);
	}

	/**
	 * 更新探针状态
	 *
	 * @param reqDto
	 * @return
	 * @throws Exception
	 */
	@Override
	public R updateProbeStatus(ConfProbeManage reqDto) {
		// 查询
		ConfProbeManage eo = probeManageMapper.queryById(reqDto.getId());
		if (null != eo) {
			String ip = eo.getIp();
			try {
				String propertySource = nacosConfigManager.getConfigService().getConfig(ip + "_common_config.ini", "UDPROBE_CONF", 1000);
				//如果获取不到相关配置文件, 也默认 获取探针失败
				if (propertySource != null) {
					ByteArrayInputStream inputStream = new ByteArrayInputStream(propertySource.getBytes());
					Ini wini = new Wini(inputStream);
					if (wini.containsKey("business_common")) {
						Ini.Section businessCommon = wini.get("business_common");
						businessCommon.put("device_is_active", reqDto.getIsStatus() == 1);
						ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
						wini.store(outputStream);
						String iniString = outputStream.toString();
						boolean publishConfig = nacosConfigManager.getConfigService().publishConfig(ip + "_common_config.ini", "UDPROBE_CONF", iniString);
						log.info("探针IP:" + ip + "--------------------失活成功！！！！---------------------");
						if (publishConfig) {
							probeManageMapper.batchUpdateStatus(Arrays.asList(reqDto.getId()), reqDto.getIsStatus());
						} else {
							log.info("探针IP:" + ip + "----激活失败!");
							return R.failed("改变探针状态失败!");
						}
						return R.ok("修改探针状态成功");
					}
				}

			} catch (Exception e) {
				log.error("改变探针状态失败: {}", e.getMessage());
				return R.failed("改变探针状态失败!");
			}
		}
		return R.failed("改变探针状态失败!");
	}

	/**
	 * 同步业务配置
	 *
	 * @param reqDto
	 * @return
	 */
	@Override
	public R syncBusiness(ConfProbeManage reqDto) {
//		进行同步操作时，将所需要进行同步业务配置的探针设备的同步状态设置成“同步中”
		List<ConfProbeManage> probeManageEoList = probeManageMapper.selectByIds(reqDto.getIdList());
		probeManageEoList.forEach(probeManageEo -> {
			probeMaps.put(probeManageEo.getIp(),"同步中");
		});
		List<ConfResource> resultEos = confResourceService.queryResourceCodeByStatus(ResourceStatusEnum.CONFIRMED.getStatus());
		// 过滤之前的数据
		List<ConfResource> businessResources = new ArrayList<>();
		List<String> list = new ArrayList<>();
		Map<String, ConfResource> resourceMap = new HashMap<>();
		if (CollectionUtils.isNotEmpty(resultEos)) {
			for (ConfResource pojo : resultEos) {
				list.add(pojo.getResourceCode());
				resourceMap.put(pojo.getResourceCode(), pojo);
			}
			//查询所有资源识别关键字
			List<ConfKeyword> identifyKeyEoList = confKeywordService.selectByResourceCodes(list);
//			查询所有父资源及其资源所有专属指标
			List<ConfExclusiveIndicator> exclusiveIndicatorsVoList = confExclusiveIndicatorService.selectByResourceCodes(list);
//			查询所有父资源aes解密信息
			List<ConfDecrypt> aesDecodeEoList = confDecryptService.selectResourceCodes(list);

			//用以同一资源专属指标去重
			Map<String, String> eiCode = new HashMap<>();
			//关键字 资源编码- 关键字的映射
			for (ConfKeyword ik : identifyKeyEoList) {
				resourceMap.get(ik.getResourceCode()).getKeys().add(ik);
			}

			for (ConfExclusiveIndicator ei : exclusiveIndicatorsVoList) {
				if (eiCode.get(ei.getResourceCode() + "|" + ei.getEiCode()) == null) {
					resourceMap.get(ei.getResourceCode()).getInd().add(ei);  //专属指标
					eiCode.put(ei.getResourceCode() + "|" + ei.getEiCode(), ei.getResourceCode() + "|" + ei.getEiCode());
				}
			}

			for (ConfDecrypt adv : aesDecodeEoList) {
				resourceMap.get(adv.getResourceCode()).getAed().add(adv);
			}

			for (Map.Entry<String, ConfResource> entry : resourceMap.entrySet()) {
				ConfResource br = entry.getValue();
				if (br.getKeys() != null && br.getKeys().size() > 0 && br.getInd() != null && br.getInd().size() > 0) {
					businessResources.add(br);
				}
			}

			if (businessResources.size() == 0) {
				log.info("没有符合条件的同步业务配置！！！");
//                reqDto.getIdList().forEach(integer -> {
//                    probeMaps.put(integer,"同步失败，没有符合条件的同步业务配置("+ DateTool.yyyy_MM_dd_HH_mm_ss(new Date())+")");
//                });
				probeManageEoList = probeManageMapper.selectByIds(reqDto.getIdList());
				probeManageEoList.forEach(probeManageEo -> {
					probeMaps.put(probeManageEo.getIp(),"同步失败，没有符合条件的同步业务配置("+ DateTool.yyyy_MM_dd_HH_mm_ss(new Date())+")");
				});
				return R.failed("没有符合条件的同步业务配置");
			}
			// 排序
			bubbleSort(businessResources);
			try {
				//send for probe
				SyncBusinessRespDto respDto = sendToProbeForBusiness(businessResources, reqDto);
				return R.ok(respDto);
			} catch (Exception e) {
				log.info("同步业务配置异常:", e);
				probeManageEoList = probeManageMapper.selectByIds(reqDto.getIdList());
				probeManageEoList.forEach(probeManageEo -> {
					probeMaps.put(probeManageEo.getIp(),"同步失败，没有符合条件的同步业务配置("+ DateTool.yyyy_MM_dd_HH_mm_ss(new Date())+")");
				});
				return R.failed("同步业务配置异常");
			}
		}
		return R.ok();

	}


	/**
	 * 冒泡排序算法( 迁移2.5逻辑)
	 *
	 * @return 对业务资源顺序进行重新排序
	 * 1.遍历所有的业务服务资源，假如业务服务资源1和2的的关键字的source为都为URL，1的fuzzyMatching的值为：
	 * AAA/BBB 2的fuzzyMatching的值为：AAA/ 最后出来的数据应该是 fuzzyMatching值较长的在前面
	 * 2.如果某个业务服务资源不存在URL，默认为业务服务资源的第一个关键字排序
	 */
	private void bubbleSort(List<ConfResource> businessResources) {
		ConfResource[] array = businessResources.toArray(new ConfResource[businessResources.size()]);
		ConfResource temp = null;
		List<ConfKeyword> identifyKeyList = null;
		List<ConfKeyword> identifyKeyList2 = null;
		String fuzzyMatching = null;
		String fuzzyMatching2 = null;
		for (int i = 0; i < array.length; i++) {
			for (int j = array.length - 1; j > i; j--) {
				identifyKeyList = array[j - 1].getKeys();
				identifyKeyList2 = array[j].getKeys();
				for (ConfKeyword identifyKey : identifyKeyList) {
					if ("URL".equals(identifyKey.getSource())) {
						fuzzyMatching = identifyKey.getMatchStr();
						break;
					} else {
						fuzzyMatching = identifyKeyList.get(0).getMatchStr();
					}
				}
				for (ConfKeyword identifyKey : identifyKeyList2) {
					if ("URL".equals(identifyKey.getSource())) {
						fuzzyMatching2 = identifyKey.getMatchStr();
						break;
					} else {
						fuzzyMatching2 = identifyKeyList.get(0).getMatchStr();
					}
				}
				if (fuzzyMatching.compareTo(fuzzyMatching2) < 0) {
					temp = array[j];
					array[j] = array[j - 1];
					array[j - 1] = temp;
				}
			}
		}
		ListIterator<ConfResource> iterator = businessResources.listIterator();
		for (int i = 0; i < array.length; i++) {
			iterator.next();
			iterator.set(array[i]);
		}
	}

	/**
	 * 同步到探针
	 *
	 * @param businessResources
	 * @param reqDto
	 */
	private SyncBusinessRespDto sendToProbeForBusiness(List<ConfResource> businessResources, ConfProbeManage reqDto) throws Exception {
		//本次已经同步的ip，不再执行同步，新建set保存已经同步的ip，
		HashSet<String> handleredIps=new HashSet<>();

		SyncBusinessRespDto respDto = new SyncBusinessRespDto();
		List<Integer> idList = reqDto.getIdList();
		Document document = getBOMCDocument(businessResources);
		byte[] data = document.asXML().getBytes();
		String xml = document.asXML();
		int xmlLength = data.length;
		log.info("xmlLength: " + xmlLength);
		int count = 0;//统计成功的个数
		List<Integer> failIpList = new ArrayList<>(idList); //统计失败的id
		List<Integer> successIdList = new ArrayList<>(); //统计成功的id
		for (Integer id : idList) {
			try {
				ConfProbeManage probeManageEo = new ConfProbeManage();
				probeManageEo.setId(id);
				List<ConfProbeManage> probeManageEoList = probeManageMapper.selectByIds(Arrays.asList(id));
				if (!CollectionUtils.isEmpty(probeManageEoList)) {
					String ip = probeManageEoList.get(0).getIp();
					//
					if (handleredIps.contains(ip)) {
						log.info("此次(" + ip + ")已同步，不可再次同步");
						continue;
					} else {
						handleredIps.add(ip);
					}
					boolean updateFlag = nacosConfigManager.getConfigService().publishConfig(ip + "_business_config.xml", "UDPROBE_CONF", xml.toString());
					if (updateFlag) { //判断探针返回的状态码，如果为103则同步成功
						count++;
						failIpList.remove(id);
						successIdList.add(id);
						probeMaps.put(ip, "同步成功(" + DateTool.yyyy_MM_dd_HH_mm_ss(new Date()) + ")");
						log.info("探针ip:" + ip + "--同步业务配置成功!--返回码:");
					} else {
						probeMaps.put(ip, "同步失败(" + DateTool.yyyy_MM_dd_HH_mm_ss(new Date()) + ")");
						log.info("探针ip:" + ip + "--同步业务配置失败!--返回码:");
					}
				}
			} catch (Exception e) {
				log.error("探针服务器交互异常!" + e);
				if (count == 0) {
					respDto.setFailIds(failIpList);
				} else {
					respDto.setCount(count);
					respDto.setTotal(idList.size());
					respDto.setFailIds(failIpList);
					respDto.setSuccessIds(successIdList);
				}
				return respDto;
			}
		}
		if (count == 0) {
			respDto.setFailIds(failIpList);
		} else {
			respDto.setCount(count);
			respDto.setTotal(idList.size());
			respDto.setFailIds(failIpList);
			respDto.setSuccessIds(successIdList);
		}
		return respDto;
	}


	/**
	 * 封装同步文件
	 *
	 * @param resList
	 * @return
	 */
	public Document getBOMCDocument(List<ConfResource> resList) {
		Document document = DocumentHelper.createDocument();
		// 根节点
		Element rootElement = document.addElement("businessConfig");
		if (resList != null && resList.size() > 0) {
			for (ConfResource busRes : resList) {
				// business数据节点
				Element businessElement = XmlUtils.createSubElement(rootElement, "business", "");
				XmlUtils.createSubElement(businessElement, "number", "0");
				XmlUtils.createSubElement(businessElement, "logo", "0");
				XmlUtils.createSubElement(businessElement, "id", busRes.getId() == null ? "" : busRes.getId() + "");
				XmlUtils.createSubElement(businessElement, "name", busRes.getName() == null ? "" : busRes.getName());
				XmlUtils.createSubElement(businessElement, "businessCode",
						busRes.getResourceCode() == null ? "" : busRes.getResourceCode());

				// 步骤节点
				Element stepsElement = XmlUtils.createSubElement(businessElement, "steps", " ");
				Element stepElement = XmlUtils.createSubElement(stepsElement, "step", "");
				XmlUtils.createSubElement(stepElement, "id", "0");
				XmlUtils.createSubElement(stepElement, "name", "0");
				XmlUtils.createSubElement(stepElement, "number", "0");

				Element nodeElement = XmlUtils.createSubElement(stepElement, "node", "");
				XmlUtils.createSubElement(nodeElement, "netseg", "0");
				XmlUtils.createSubElement(nodeElement, "netProtocol",
						busRes.getAgreementResourceCode() != null ? busRes.getAgreementResourceCode() : "0");
				XmlUtils.createSubElement(nodeElement, "networkType", "0");

				// 关键字节点
				List<ConfKeyword> keyset = busRes.getKeys();
				Element keysElement = XmlUtils.createSubElement(nodeElement, "keys", "");
				Iterator<ConfKeyword> itkeys = keyset.iterator();
				while (itkeys.hasNext()) {
					ConfKeyword key = itkeys.next();
					Element keyElement = XmlUtils.createSubElement(keysElement, "key", "");
					XmlUtils.createSubElement(keyElement, "source", key.getSource() == null ? "" : key.getSource());
					// XmlUtils.createSubElement(keyElement, "keyName",
					// key.getKeyVal()==null?"":key.getKeyVal());
					XmlUtils.createSubElement(keyElement, "keyName", key.getKeyword() == null ? "" : key.getKeyword());
					XmlUtils.createSubElement(keyElement, "fuzzyMatching",
							key.getMatchStr() == null ? "" : key.getMatchStr());
				}
				//aes解密节点
				List<ConfDecrypt> aeslist = busRes.getAed();
				Element aesElement = XmlUtils.createSubElement(nodeElement, "encs", "");
				Iterator<ConfDecrypt> itaes = aeslist.iterator();
				while (itaes.hasNext()) {
					ConfDecrypt aes = itaes.next();
					Element aesdElement = XmlUtils.createSubElement(aesElement, "enc", "");
					XmlUtils.createSubElement(aesdElement, "source", aes.getSource() == null ? "" : aes.getSource());
					XmlUtils.createSubElement(aesdElement, "keyword", aes.getKeyword() == null ? "" : aes.getKeyword());
					XmlUtils.createSubElement(aesdElement, "likeMatching", aes.getMatchRegular() == null ? "" : aes.getMatchRegular());
					XmlUtils.createSubElement(aesdElement, "encAlg", aes.getEcryptAlg() == null ? "" : aes.getEcryptAlg());
					XmlUtils.createSubElement(aesdElement, "encMode", aes.getEncodeType() == null ? "" : aes.getEncodeType());
					XmlUtils.createSubElement(aesdElement, "fillVal", aes.getFillValue() == null ? "" : aes.getFillValue());
					XmlUtils.createSubElement(aesdElement, "encBin", aes.getEcryptBit() == null ? "" : aes.getEcryptBit().toString());
					XmlUtils.createSubElement(aesdElement, "secretKey", aes.getSecretKey() == null ? "" : aes.getSecretKey());
					XmlUtils.createSubElement(aesdElement, "offset",   aes.getOffset() == null ? "" : aes.getOffset().toString());
					XmlUtils.createSubElement(aesdElement, "encode", aes.getEcryptMode() == null ? "" : aes.getEcryptMode());
				}
				// 指标节点
				List<ConfExclusiveIndicator> indlist = busRes.getInd();
				Element indicatorsElement = XmlUtils.createSubElement(nodeElement, "flags", "");
				Iterator<ConfExclusiveIndicator> iteicts = indlist.iterator();
				while (iteicts.hasNext()) {
					ConfExclusiveIndicator inditcator = iteicts.next();
					Element indicatorElement = XmlUtils.createSubElement(indicatorsElement, "flag", "");
					if ("ISVALUE".equals(inditcator.getName()) || "ISEXIT".equals(inditcator.getName()) || "SESSIONID".equals(inditcator.getName())) {
						XmlUtils.createSubElement(indicatorElement, "name", inditcator.getName());
					} else {
						XmlUtils.createSubElement(indicatorElement, "name", inditcator.getEiCode() + ":" + inditcator.getName());
					}
					XmlUtils.createSubElement(indicatorElement, "source",
							inditcator.getSource() == null ? "" : inditcator.getSource());
					XmlUtils.createSubElement(indicatorElement, "keyName",
							inditcator.getKeyword() == null ? "" : inditcator.getKeyword());
					XmlUtils.createSubElement(indicatorElement, "valueType",
							inditcator.getKeywordType() == null ? "" : inditcator.getKeywordType());
					XmlUtils.createSubElement(indicatorElement, "cal",
							inditcator.getFormatStr() == null ? "" : inditcator.getFormatStr());
					XmlUtils.createSubElement(indicatorElement, "likeMatching",
							inditcator.getMatchRegular() == null ? "" : inditcator.getMatchRegular());


					JSONObject jsonObject = JSONUtil.parseObj(inditcator.getDetail());

					XmlUtils.createSubElement(indicatorElement, "isCheckAll",
							String.valueOf(Optional.ofNullable(jsonObject.get("isFullExtraction")).orElse("0")));
					XmlUtils.createSubElement(indicatorElement, "isSaveOri",
							String.valueOf(Optional.ofNullable(jsonObject.get("isRetainOri")).orElse("0")));
				}

				// IP端口节点
				// Element ipPortsElement =
				// XmlUtils.createSubElement(nodeElement, "groups", "");

			}
		}

		return document;
	}


	/**
	 * 同步协议
	 *
	 * @param ip
	 * @return
	 */
	//todo 同步协议
	@Override
	public R<String> syncProtocolByIp(String ip) {
		List<ConfProtocol> resultList = new ArrayList<>();
		try {
			String configProperty = nacosConfigManager.getConfigService().getConfig(ip + "_probeConfigDetail_json", "UDPROBE_CONF", 5000);
			log.info("接收到获取app_proto_macro.json文件应用层协议宏成功:" + configProperty);
			JSONObject jsonObject = JSONUtil.parseObj(configProperty);
			if (jsonObject.get("dataList") != null) {
				JSONArray dataList = (JSONArray) jsonObject.get("dataList");
				for (Object data : dataList) {
					if(data instanceof List){
						List<String> probe = (List<String>) data;
						ConfProtocol mmp = new ConfProtocol();
						if (probe.size() >0) {
							mmp.setName(probe.get(0));
						}
						if (probe.size() > 1) {
							mmp.setProtocolId(Integer.valueOf(probe.get(1)));
						}
						if (probe.size() > 2) {
							mmp.setRegularExpressions(probe.get(2));
						}
						resultList.add(mmp);
					}
				}
				//查询所有的协议
				List<ConfProtocol> needInsertList = new ArrayList<>();
				List<ConfProtocol> agreementResourceList = confProtocolService.list();
				if (CollectionUtils.isNotEmpty(agreementResourceList)) {
					for (ConfProtocol probe : resultList) {
						// 标识是否新增
						int count = 0;
						for (ConfProtocol mysqlDb : agreementResourceList) {
							// 匹配上 name 且 (协议id不相等或者表达式不等). 需要进行更新
							if (probe.getName().equals(mysqlDb.getName())) {
								count++;
								if (!probe.getProtocolId().equals(mysqlDb.getProtocolId())
										|| !probe.getRegularExpressions().equals(mysqlDb.getRegularExpressions())) {
									confProtocolService.updateAgreementResource(probe);
								}
								break;
							}
						}
						if (0 == count) {
							probe.setResourceCode("AR-AP-" + probe.getName() + "-");
							probe.setDecoded(0);
							probe.setIsStatus(1);
							probe.setWhetherEnable(1);
							probe.setResourceType("AR-AP-" + probe.getName());
							probe.setCreateBy(getUserName());
							probe.setModifier(getUserName());
							needInsertList.add(probe);
						}
					}
				}
				if (CollectionUtils.isNotEmpty(needInsertList)) {
					// 查询最大的
					long count = confProtocolService.count();

					for (ConfProtocol agreementResource : needInsertList) {
						count++;
						LocalDateTime now = LocalDateTime.now();
						String resourceCoding = agreementResource.getResourceCode();
						agreementResource.setResourceCode(resourceCoding + count);
						agreementResource.setModifierTime(now);
						agreementResource.setCreateTime(now);
					}
					// 保存
					confProtocolService.saveBatch(needInsertList);
				}
			}
		} catch (NacosException e) {
			log.error("同步失败: {}", e.getMessage());
			R.failed("同步失败");
		}
		return R.ok("同步成功");
	}

	/**
	 * 清空Ip过滤配置
	 *
	 * @param reqDto
	 * @return
	 */
	@Override
	public R cleanIp(ConfProbeManage reqDto) {
		SyncBusinessRespDto respDto = new SyncBusinessRespDto();
		List<Integer> idList = reqDto.getIdList();
		int count = 0;
		List<Integer> resultIpList = new ArrayList<>(idList);
		List<Integer> successIdList = new ArrayList<>();
		for (Integer id : idList) {
			List<ConfProbeManage> probeManageEoList = probeManageMapper.selectByIds(Arrays.asList(id));
			if (CollectionUtils.isNotEmpty(probeManageEoList)) {
				String ip = probeManageEoList.get(0).getIp();
				try {


					// 创建Document对象
					Document document = DocumentHelper.createDocument();

					// 创建根节点config
					Element rootElement = document.addElement("config");

					// 创建white_list节点
					Element whiteListElement = rootElement.addElement("white_list");

					// 设置输出格式
					OutputFormat format = OutputFormat.createPrettyPrint();
					format.setSuppressDeclaration(true); // 不生成XML声明

					// 创建XMLWriter对象，并将XML内容写入StringWriter
					StringWriter stringWriter = new StringWriter();
					XMLWriter xmlWriter = new XMLWriter(stringWriter, format);
					xmlWriter.write(document);
					xmlWriter.flush();
					xmlWriter.close();
					boolean updateFlag = nacosConfigManager.getConfigService().publishConfig(ip + "_prehandle.xml", "UDPROBE_CONF", stringWriter.toString());
					if (updateFlag) {
						log.info("探针IP:" + ip + "--过滤IP清空成功！");
						resultIpList.remove(id);
						successIdList.add(id);
						count++;
						//把组件Ip的状态全部归0，非过滤
						confComponentIpService.resetIpFilter();
					} else {
						log.info("探针ip" + ip + "--过滤IP清空失败！");
					}

				} catch (Exception e) {
					log.info("连接超时,清空过滤IP失败!" + e);
					if (count == 0) {
						respDto.setFailIds(resultIpList);
					} else {
						respDto.setCount(count);
						respDto.setTotal(idList.size());
						respDto.setFailIds(resultIpList);
						respDto.setSuccessIds(successIdList);
					}
					return R.failed("连接超时,清空过滤IP失败");
				}
			}
		}
		if (count == 0) {
			respDto.setFailIds(resultIpList);
		} else {
			respDto.setCount(count);
			respDto.setTotal(idList.size());
			respDto.setFailIds(resultIpList);
			respDto.setSuccessIds(successIdList);
		}
		return R.ok(respDto);
	}

	/**
	 * 同步ip过滤配置
	 *
	 * @param reqDto
	 * @return
	 */
	@Override
	public R syncIp(ConfProbeManage reqDto) {
		List<ConfComponentIp> componentManagementVoList = confComponentIpService.selectByIsFilter(1);
		if (CollectionUtils.isNotEmpty(componentManagementVoList)) {
			StringBuffer ip = new StringBuffer();
			for (ConfComponentIp managementVo : componentManagementVoList) {
				ip.append(managementVo.getIp() + "|");
			}
			String xml = ip.toString();
			byte[] data = ip.toString().getBytes();
			int length = data.length;
			log.info("同步的ip:" + xml + "Length:" + length);
			// 同步ip
			return sendToProbeForIp(reqDto, xml, componentManagementVoList);
		}
		return R.failed("没有可同步的过滤Ip");
	}


	/**
	 * @param reqDto
	 * @param xml
	 * @param componentManagementVoList
	 */
	private R sendToProbeForIp(ConfProbeManage reqDto, String xml, List<ConfComponentIp> componentManagementVoList) {
		List<Integer> idList = reqDto.getIdList();
		int count = 0;
		SyncBusinessRespDto respDto = new SyncBusinessRespDto();
		List<Integer> failIpList = new ArrayList<>(idList); //统计失败的id
		List<Integer> successIdList = new ArrayList<>(); //统计成功的id
		for (Integer id : idList) {
			try {
				List<ConfProbeManage> probeManageEoList = probeManageMapper.selectByIds(Arrays.asList(id));
				if (!CollectionUtils.isEmpty(probeManageEoList)) {
					String ip = probeManageEoList.get(0).getIp();
					// 创建Document对象
					Document document = DocumentHelper.createDocument();

					// 创建根节点config
					Element rootElement = document.addElement("config");

					// 创建white_list节点
					Element whiteListElement = rootElement.addElement("white_list");

					// 创建ip节点并设置文本内容
					Element ipElement = whiteListElement.addElement("ip");
					ipElement.setText(ip);

					// 设置输出格式
					OutputFormat format = OutputFormat.createPrettyPrint();
					format.setSuppressDeclaration(true); // 不生成XML声明

					// 创建XMLWriter对象，并将XML内容写入StringWriter
					StringWriter stringWriter = new StringWriter();
					XMLWriter xmlWriter = new XMLWriter(stringWriter, format);
					xmlWriter.write(document);
					xmlWriter.flush();
					xmlWriter.close();
					boolean updateFlag = nacosConfigManager.getConfigService().publishConfig(ip + "_prehandle.xml", "UDPROBE_CONF", stringWriter.toString());
					//处理探针同步的返回结果
					if (updateFlag) {
						if (updateFlag) {
							failIpList.remove(id);
							successIdList.add(id);
							log.info("探针IP:" + ip + "同步过滤IP成功！--返回码:");
							count++;
						} else {
							log.info("探针IP:" + ip + "同步过滤IP失败！--返回码:");
						}
					}
				}
			} catch (Exception e) {
				log.info("同步过滤IP超时!" + e);
				if (count == 0) {
					respDto.setFailIds(failIpList);
				} else {
					respDto.setCount(count);
					respDto.setTotal(idList.size());
					respDto.setFailIds(failIpList);
					respDto.setSuccessIds(successIdList);
				}
				return R.failed("同步过滤IP超时");
			}
		}
		// 遍历同步完成后,进行跟新操作
		if (count == 0) {
			respDto.setFailIds(failIpList);
		} else {
			respDto.setCount(count);
			respDto.setTotal(idList.size());
			respDto.setFailIds(failIpList);
			respDto.setSuccessIds(successIdList);
		}
		//同步的时候改变对应的同步状态
		List<Integer> managementIdList = componentManagementVoList.stream().map(ConfComponentIp::getId).collect(Collectors.toList());
		confComponentIpService.batchUpdateSyncState(managementIdList, 1);
		return R.ok(respDto);
	}


	/**
	 * @param is
	 * @param data
	 * @param length
	 * @return
	 * @throws IOException
	 */
	private void readTillLength(InputStream is, byte[] data, int length) throws IOException {
		int hasRead = 0;
		int everyRead = 0;
		while (hasRead < length) {
			everyRead = is.read(data, hasRead, length - hasRead);
			if (everyRead > 0) {
				hasRead = hasRead + everyRead;
			} else if (everyRead == -1) {
				throw new IOException("is.read(data,hasRead,length-hasRead)：" + everyRead + "流已关闭");
			}

		}
	}



	/**
	 * 获取登录人信息
	 *
	 * @return
	 */
	private String getUserName() {
		return SecurityUtils.getUser().getUsername();
	}


}
